home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / lfslib / lfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-12  |  16.8 KB  |  595 lines

  1. /* 
  2.  * lfs.c --
  3.  *
  4.  *    Routines for accessing LFS file systems data structures from
  5.  *    an user level program.
  6.  *
  7.  * Copyright 1990 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/proto.c,v 1.3 90/01/12 12:03:36 douglis Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include "lfslib.h"
  22. #include "lfslibInt.h"
  23. #ifdef _HAS_PROTOTYPES
  24. #include <varargs.h>
  25. #include <sys/types.h>
  26. #endif /* _HAS_PROTOTYPES */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <sys/file.h>
  30. #include <unistd.h>
  31. #include <bstring.h>
  32. #include <time.h>
  33. #include <hash.h>
  34. #include <list.h>
  35.  
  36. extern int open();
  37.  
  38. /*
  39.  *----------------------------------------------------------------------
  40.  *
  41.  * LfsLoadFileSystem --
  42.  *
  43.  *    Load an LFS file system into memory.
  44.  *
  45.  * Results:
  46.  *    A Lfs structure, NULL if the load didn't complete.
  47.  *
  48.  * Side effects:
  49.  *    None.
  50.  *
  51.  *----------------------------------------------------------------------
  52.  */
  53.  
  54. Lfs *
  55. LfsLoadFileSystem(programName, deviceName, blockSize,  superBlockOffset, flags)
  56.     char *programName;    /* Program name. */
  57.     char *deviceName;    /* Device name to open. */
  58.     int     blockSize;    /* Block size of file system. */
  59.     int     superBlockOffset; /* Offset of the super block. */
  60.     int     flags;        /* Flags for open. */
  61. {
  62.     Lfs    *lfsPtr;
  63.     int     diskFd;
  64.     int       maxCheckPointSize;
  65.     LfsCheckPointHdr    checkPointHdr[2], *checkPointHdrPtr;
  66.     char        *checkPointPtr, *trailerPtr;
  67.     LfsCheckPointRegion *regionPtr;
  68.     LfsCheckPointTrailer *trailPtr;
  69.     char        buffer[LFS_SUPER_BLOCK_SIZE];
  70.     int            choosenOne;
  71.     Boolean        error;
  72.  
  73.     diskFd = open(deviceName, flags, 0);
  74.     if (diskFd < 0) {
  75.     fprintf(stderr,"%s:", programName);
  76.     perror("opening device");
  77.     return (Lfs *) NULL;
  78.     }
  79.     lfsPtr = (Lfs *) calloc(1, sizeof(Lfs));
  80.     if (lfsPtr == (Lfs *) NULL) {
  81.     fprintf(stderr,"%s: Out of memory\n", programName);
  82.     goto    cleanupAndReturnError;
  83.     }
  84.     lfsPtr->diskFd = diskFd;
  85.     lfsPtr->diskCache = (ClientData) NULL;
  86.     lfsPtr->superBlockOffset = superBlockOffset;
  87.     lfsPtr->deviceName = deviceName;
  88.     lfsPtr->programName = programName;
  89.     /*
  90.      * Set to block size so LfsDiskRead will work.
  91.      */
  92.     lfsPtr->superBlock.hdr.blockSize = blockSize;
  93.  
  94.     /*
  95.      * Read in the super block header. We put much trust in the magic number
  96.      * of the file system.
  97.      */
  98.     if (LfsDiskRead(lfsPtr, superBlockOffset, LFS_SUPER_BLOCK_SIZE, 
  99.         (char *)buffer) != LFS_SUPER_BLOCK_SIZE) {
  100.     fprintf(stderr,"%s:Can't read superblock.\n", deviceName);
  101.     goto    cleanupAndReturnError;
  102.     }
  103.     bcopy(buffer, (char *) &lfsPtr->superBlock, sizeof(lfsPtr->superBlock));
  104.     if (lfsPtr->superBlock.hdr.magic != LFS_SUPER_BLOCK_MAGIC) {
  105.     fprintf(stderr,"%s:Bad magic number for filesystem\n", deviceName);
  106.     goto    cleanupAndReturnError;
  107.     }
  108.  
  109.     /*
  110.      * Examine the two checkpoint areas to locate the checkpoint area with the
  111.      * newest timestamp.
  112.      */
  113.     if (LfsDiskRead(lfsPtr, lfsPtr->superBlock.hdr.checkPointOffset[0],
  114.         sizeof(LfsCheckPointHdr), (char *) (checkPointHdr+0)) != 
  115.     sizeof(LfsCheckPointHdr)) {
  116.     fprintf(stderr,"%s:Can't read checkPointHeader 0.\n", deviceName);
  117.     checkPointHdr[0].timestamp = 0;
  118.     }
  119.     if (LfsDiskRead(lfsPtr, lfsPtr->superBlock.hdr.checkPointOffset[1],
  120.         sizeof(LfsCheckPointHdr), (char *) (checkPointHdr+1))  != 
  121.     sizeof(LfsCheckPointHdr)) {
  122.     fprintf(stderr,"%s:Can't read checkPointHeader 1.\n", deviceName);
  123.     checkPointHdr[1].timestamp = 0;
  124.     }
  125.     /*
  126.      * Choose a checkpoint and read it in.
  127.      */
  128.     if (checkPointHdr[0].timestamp < checkPointHdr[1].timestamp) {
  129.      choosenOne = 1;
  130.     } else {
  131.      choosenOne = 0;
  132.     }
  133.     lfsPtr->checkPoint.timestamp = checkPointHdr[choosenOne].timestamp;
  134.     lfsPtr->checkPoint.nextArea = !choosenOne;
  135.  
  136.     maxCheckPointSize = lfsPtr->superBlock.hdr.maxCheckPointBlocks * 
  137.                 blockSize;
  138.     checkPointPtr = malloc(maxCheckPointSize);
  139.     if (checkPointPtr == (char *) NULL) {
  140.     fprintf(stderr,"%s:Out of memory\n", programName);
  141.     goto    cleanupAndReturnError;
  142.     }
  143.     lfsPtr->checkPoint.buffer = checkPointPtr;
  144.     lfsPtr->checkPoint.maxSize = maxCheckPointSize;
  145.  
  146.     lfsPtr->checkPointHdrPtr = (LfsCheckPointHdr *) checkPointPtr;
  147.  
  148.     if (LfsDiskRead(lfsPtr, lfsPtr->superBlock.hdr.checkPointOffset[choosenOne],
  149.         maxCheckPointSize, checkPointPtr) != maxCheckPointSize) {
  150.     fprintf(stderr,"%s:Can't read checkPoint %d\n", deviceName, choosenOne);
  151.     goto    cleanupAndReturnError;
  152.     }
  153.  
  154.  
  155.     checkPointHdrPtr = (LfsCheckPointHdr *) checkPointPtr;
  156.     trailerPtr = checkPointPtr + checkPointHdrPtr->size - 
  157.                     sizeof(LfsCheckPointTrailer);
  158.     trailPtr = (LfsCheckPointTrailer *) trailerPtr;
  159.     if (trailPtr->timestamp != checkPointHdrPtr->timestamp) {
  160.     fprintf(stderr,"%s:Header timestamp %d doesn't match trailer timestamp %d\n", deviceName, checkPointHdrPtr->timestamp, trailPtr->timestamp);
  161.     goto    cleanupAndReturnError;
  162.     }
  163.     lfsPtr->name = checkPointHdrPtr->domainPrefix;
  164.     bcopy(checkPointPtr + checkPointHdrPtr->size, (char *) &lfsPtr->stats,
  165.         sizeof(lfsPtr->stats));
  166.     checkPointPtr = checkPointPtr + sizeof(LfsCheckPointHdr);
  167.  
  168.     /*
  169.      * Load the LFS metadata from the last checkpoint. 
  170.      * For each checkpoint region .....
  171.      */
  172.     error = FALSE;
  173.     while ((checkPointPtr < trailerPtr) && !error) { 
  174.     regionPtr = (LfsCheckPointRegion *) checkPointPtr;
  175.     if (regionPtr->size == 0) {
  176.         break;
  177.     }
  178.     switch (regionPtr->type) {
  179.         case LFS_SEG_USAGE_MOD:
  180.         error = LfsLoadUsageArray(lfsPtr, 
  181.                      regionPtr->size - sizeof(*regionPtr),
  182.                     (char *) (regionPtr+1));
  183.         break;
  184.         case LFS_DESC_MAP_MOD:
  185.         error = LfsLoadDescMap(lfsPtr, 
  186.                    regionPtr->size - sizeof(*regionPtr),
  187.                     (char *) (regionPtr+1));
  188.         break;
  189.         case LFS_FILE_LAYOUT_MOD:
  190.         if (regionPtr->size != sizeof(*regionPtr)) {
  191.             error = TRUE;
  192.             fprintf(stderr,"%s:Bad size %d for FILELAYOUT checkpoint\n",
  193.                     deviceName,regionPtr->size);
  194.         }
  195.         break;
  196.         default: 
  197.         fprintf(stderr,"%s:Unknown region type %d of size %d\n",
  198.                 deviceName,
  199.                 regionPtr->type, regionPtr->size);
  200.         break;
  201.     }
  202.     checkPointPtr += regionPtr->size;
  203.     }
  204.     List_Init(&lfsPtr->fileLayout.activeFileListHdr);
  205.     if (!error) {
  206.     return lfsPtr;
  207.     }
  208. cleanupAndReturnError:
  209.     return (Lfs *) NULL;
  210.  
  211. }
  212.  
  213.  
  214. /*
  215.  *----------------------------------------------------------------------
  216.  *
  217.  * LfsCheckPointFileSystem --
  218.  *
  219.  *    Checkpoint the state of a file system generated by a user  program.
  220.  *
  221.  * Results:
  222.  *    SUCCESS if the file system was successfully checkpointed. 
  223.  *
  224.  * Side effects:
  225.  *    None.
  226.  *
  227.  *----------------------------------------------------------------------
  228.  */
  229.  
  230. ReturnStatus
  231. LfsCheckPointFileSystem(lfsPtr, flags)
  232.     Lfs        *lfsPtr;    /* File system to be checkpointed. */
  233.     int flags;        /* Flags for checkpoint. */
  234. {
  235.     LfsCheckPointHdr    *checkPointHdrPtr;
  236.     int            size, blocks, bytes;
  237.     LfsCheckPointTrailer *trailerPtr;
  238.     int        diskAddr;
  239.     ReturnStatus    status, count;
  240.     char        *bufferPtr;
  241.  
  242.     bufferPtr = lfsPtr->checkPoint.buffer;
  243.     checkPointHdrPtr = (LfsCheckPointHdr *) bufferPtr;
  244.  
  245.  
  246.     status = LfsSegCheckPoint(lfsPtr, (char *)(checkPointHdrPtr+1),
  247.                 &size);
  248.     if ((status != SUCCESS) || (size < 0)) {
  249.     return status;
  250.     }
  251.     /*
  252.      * Fill in check point header and trailer.
  253.      */
  254.     checkPointHdrPtr->timestamp = LfsGetCurrentTimestamp(lfsPtr);
  255.     checkPointHdrPtr->size = size + sizeof(LfsCheckPointHdr) + 
  256.              sizeof(LfsCheckPointTrailer);
  257.     checkPointHdrPtr->version = 1;
  258.     checkPointHdrPtr->detachSeconds = time(0);
  259.     trailerPtr = (LfsCheckPointTrailer *) 
  260.         (bufferPtr + size + sizeof(LfsCheckPointHdr));
  261.     trailerPtr->timestamp = checkPointHdrPtr->timestamp;
  262.     trailerPtr->checkSum = 0;
  263.  
  264.     /*
  265.      * Append the stats to the checkpoint regions.
  266.      */
  267.     bytes = checkPointHdrPtr->size + sizeof(Lfs_Stats);
  268.     blocks = LfsBytesToBlocks(lfsPtr, bytes);
  269.     bcopy ((char *) &lfsPtr->stats, (char *) (trailerPtr + 1), 
  270.         sizeof(lfsPtr->stats));
  271.     LfsOffsetToDiskAddr(
  272.     lfsPtr->superBlock.hdr.checkPointOffset[lfsPtr->checkPoint.nextArea],
  273.         &diskAddr);
  274.     count = LfsDiskWrite(lfsPtr, diskAddr, 
  275.     LfsBlocksToBytes(lfsPtr, blocks), (char *) checkPointHdrPtr);
  276.     if (count == LfsBlocksToBytes(lfsPtr, blocks)) {
  277.     /*
  278.      * Set the file system up to use the other checkpoint buffer next time.
  279.      */
  280.     lfsPtr->checkPoint.nextArea = !lfsPtr->checkPoint.nextArea;
  281.     } else {
  282.     return FAILURE;
  283.     }
  284.     return status;
  285. }
  286.  
  287. typedef struct DiskCache {
  288.     List_Links    blockList; /* List of blocks cached. */
  289.     Hash_Table    blockHashTable; /* Hash table for blocks. */
  290.     int    bytesCached;    /* Number of bytes of data in disk cache. */
  291.     int maxCacheBytes;  /* Maxnumbe of bytes that should be cached. */
  292. } DiskCache;
  293.  
  294. typedef struct DiskBlock {
  295.     List_Links links;    /* For list of blocks. MUST BE FIRST. */
  296.     int    blockOffset;    /* Offset into device of block. */
  297.     int blockSize;    /* Size of block in bytes. */
  298.     /*
  299.      * Data follows structure. 
  300.      */
  301. } DiskBlock;
  302.  
  303. static void DeleteCacheBlock _ARGS_((DiskCache *diskCachePtr, 
  304.                 DiskBlock *cacheBlockPtr));
  305.  
  306.  
  307. /*
  308.  *----------------------------------------------------------------------
  309.  *
  310.  * LfsDiskCache --
  311.  *
  312.  *    Set amount of data to cache in application
  313.  *
  314.  * Results:
  315.  *    None.
  316.  *
  317.  * Side effects:
  318.  *    None.
  319.  *
  320.  *----------------------------------------------------------------------
  321.  */
  322. void
  323. LfsDiskCache(lfsPtr, maxCacheBytes)
  324.     Lfs    *lfsPtr;
  325.     int    maxCacheBytes;
  326. {
  327.     DiskCache    *diskCachePtr = (DiskCache *) lfsPtr->diskCache;
  328.  
  329.     if (diskCachePtr == (DiskCache *) NULL) {
  330.     diskCachePtr = (DiskCache *) calloc(1, sizeof(DiskCache));
  331.     lfsPtr->diskCache = (ClientData) diskCachePtr;
  332.     List_Init(&(diskCachePtr->blockList));
  333.     Hash_InitTable(&(diskCachePtr->blockHashTable), 0, HASH_ONE_WORD_KEYS);
  334.     diskCachePtr->bytesCached = 0;
  335.     }
  336.     diskCachePtr->maxCacheBytes = maxCacheBytes;
  337. }
  338.  
  339.  
  340. /*
  341.  *----------------------------------------------------------------------
  342.  *
  343.  * DeleteCacheBlock --
  344.  *
  345.  *    Delete a block from the disk cache.
  346.  *
  347.  * Results:
  348.  *    None.
  349.  *
  350.  * Side effects:
  351.  *    None.
  352.  *
  353.  *----------------------------------------------------------------------
  354.  */
  355.  
  356. static void
  357. DeleteCacheBlock(diskCachePtr, cacheBlockPtr)
  358.     DiskCache    *diskCachePtr;
  359.     DiskBlock    *cacheBlockPtr;
  360. {
  361.     Hash_Entry *entryPtr;
  362.  
  363.     List_Remove((List_Links *) cacheBlockPtr);
  364.     entryPtr = Hash_FindEntry(&(diskCachePtr->blockHashTable),
  365.                 cacheBlockPtr->blockOffset);
  366.     Hash_DeleteEntry(&(diskCachePtr->blockHashTable), entryPtr);
  367.     diskCachePtr->bytesCached -= cacheBlockPtr->blockSize;
  368.     free((char *) cacheBlockPtr);
  369. }
  370.  
  371.  
  372. /*
  373.  *----------------------------------------------------------------------
  374.  *
  375.  * LfsDiskCacheInvalidate --
  376.  *
  377.  *    Invalidate a block range in the disk cache
  378.  *
  379.  * Results:
  380.  *    None.
  381.  *
  382.  * Side effects:
  383.  *    None.
  384.  *
  385.  *----------------------------------------------------------------------
  386.  */
  387. void
  388. LfsDiskCacheInvalidate(lfsPtr, blockOffset, blockSize)
  389.     Lfs    *lfsPtr;
  390.     int    blockOffset;
  391.     int    blockSize;
  392. {
  393.     DiskCache    *diskCachePtr = (DiskCache *) lfsPtr->diskCache;
  394.     DiskBlock *cacheBlockPtr;
  395.     Hash_Entry *entryPtr;
  396.     int    endBlock;
  397.  
  398.     if (diskCachePtr == (DiskCache *) NULL) {
  399.     return;
  400.     }
  401.     if (blockOffset == -1) {
  402.     LIST_FORALL(&(diskCachePtr->blockList), (List_Links *) cacheBlockPtr) {
  403.         DeleteCacheBlock(diskCachePtr, cacheBlockPtr);
  404.     }
  405.     return;
  406.     }
  407.     endBlock = blockOffset + 
  408.         (blockSize + LfsBlockSize(lfsPtr) - 1)/LfsBlockSize(lfsPtr);
  409.     for (; blockOffset < endBlock; blockOffset++) {
  410.     entryPtr = Hash_FindEntry(&(diskCachePtr->blockHashTable), 
  411.                 (Address)blockOffset);
  412.     if (entryPtr == (Hash_Entry *) NULL) {
  413.         continue;
  414.     }
  415.     DeleteCacheBlock(diskCachePtr, (DiskBlock *) Hash_GetValue(entryPtr));
  416.     }
  417. }
  418.  
  419.  
  420.  
  421. /*
  422.  *----------------------------------------------------------------------
  423.  *
  424.  * LfsDiskRead --
  425.  *
  426.  *    Read data from disk.
  427.  *
  428.  * Results:
  429.  *    The number of bytes returned.  -1 if error.
  430.  *
  431.  * Side effects:
  432.  *    None.
  433.  *
  434.  *----------------------------------------------------------------------
  435.  */
  436. int
  437. LfsDiskRead(lfsPtr, blockOffset, bufferSize, bufferPtr)
  438.     Lfs    *lfsPtr;    /* File system. */
  439.     int    blockOffset;    /* Block offset to start read. */
  440.     char *bufferPtr;    /* Buffer to place data. */
  441.     int     bufferSize;    /* Size of buffer. */
  442. {
  443.     int    diskFd, blockSize, status, blocks;
  444.     char *bufPtr;
  445.     DiskBlock    *cacheBlockPtr;
  446.     DiskCache    *diskCachePtr = (DiskCache *) lfsPtr->diskCache;
  447.  
  448.  
  449.     cacheBlockPtr = (DiskBlock *) NULL;
  450.     if (diskCachePtr != (DiskCache *) NULL) {
  451.     Hash_Entry *entryPtr;
  452.     Boolean new;
  453.     int    newBytes;
  454.     entryPtr = Hash_CreateEntry(&(diskCachePtr->blockHashTable),
  455.                     (Address) blockOffset, &new);
  456.     if (!new) {
  457.         cacheBlockPtr = (DiskBlock *) Hash_GetValue(entryPtr);
  458.         if (cacheBlockPtr->blockSize >= bufferSize) {
  459.         bcopy((char *) (cacheBlockPtr+1), bufferPtr, bufferSize);
  460.         List_Move((List_Links *) cacheBlockPtr, 
  461.                 LIST_ATFRONT(&(diskCachePtr->blockList)));
  462.         return bufferSize;
  463.         }
  464.         List_Remove((List_Links *) cacheBlockPtr);
  465.         cacheBlockPtr = (DiskBlock *) realloc((char *) cacheBlockPtr,
  466.                         sizeof(DiskBlock) + bufferSize);
  467.         newBytes = bufferSize - cacheBlockPtr->blockSize;
  468.         cacheBlockPtr->blockSize = bufferSize;
  469.     } else { 
  470.         newBytes = bufferSize;
  471.         cacheBlockPtr = (DiskBlock *) malloc(sizeof(DiskBlock)+bufferSize);
  472.         List_InitElement(&(cacheBlockPtr->links));
  473.         cacheBlockPtr->blockOffset = blockOffset;
  474.         cacheBlockPtr->blockSize = bufferSize;
  475.     }
  476.     Hash_SetValue(entryPtr, (ClientData) cacheBlockPtr);
  477.     while ((newBytes + diskCachePtr->bytesCached > 
  478.             diskCachePtr->maxCacheBytes) && 
  479.         !List_IsEmpty(&(diskCachePtr->blockList))) {
  480.         DeleteCacheBlock(diskCachePtr, 
  481.             (DiskBlock *) List_Last(&(diskCachePtr->blockList)));
  482.     }
  483.     List_Insert((List_Links *) cacheBlockPtr, 
  484.             LIST_ATFRONT(&(diskCachePtr->blockList)));
  485.     diskCachePtr->bytesCached += newBytes;
  486.     }
  487.  
  488.     diskFd = lfsPtr->diskFd;
  489.     blockSize = LfsBlockSize(lfsPtr);
  490.     /*
  491.      * Seek to the start of the blocks to read.
  492.      */
  493.     status = lseek(diskFd, blockOffset*blockSize, L_SET);
  494.     if (status < 0) {
  495.     fprintf(stderr,"%s:", lfsPtr->deviceName);
  496.     perror("lseek");
  497.     if (cacheBlockPtr != (DiskBlock *) NULL) {
  498.         DeleteCacheBlock(diskCachePtr,cacheBlockPtr);
  499.     }
  500.     return status;
  501.     }
  502.     /*
  503.      * Read the blocks handling the case the a request that is not a 
  504.      * multiple number of blocks by reading to a temp buffer and copying.
  505.      */
  506.     blocks = (bufferSize + blockSize-1)/blockSize;
  507.     if (bufferSize != blocks * blockSize) { 
  508.     bufPtr = malloc(blocks*blockSize);
  509.     } else {
  510.     bufPtr = bufferPtr;
  511.     }
  512.     status = read(diskFd, bufPtr, blocks*blockSize);
  513.     if (status != blocks*blockSize) {
  514.     if (status < 0) {
  515.         fprintf(stderr,"%s:", lfsPtr->deviceName);
  516.         perror("read device");
  517.         if (cacheBlockPtr != (DiskBlock *) NULL) {
  518.         DeleteCacheBlock(diskCachePtr,cacheBlockPtr);
  519.         }
  520.         return status;
  521.     }
  522.     fprintf(stderr,"%s:Short read on device %d != %d\n", lfsPtr->deviceName,
  523.         status, blocks*blockSize);
  524.     if (cacheBlockPtr != (DiskBlock *) NULL) {
  525.         DeleteCacheBlock(diskCachePtr,cacheBlockPtr);
  526.         cacheBlockPtr =  (DiskBlock *) NULL;
  527.     }
  528.     } else {
  529.     status = bufferSize;
  530.     }
  531.     if (bufPtr != bufferPtr) { 
  532.     bcopy(bufPtr, bufferPtr, bufferSize);
  533.     free(bufPtr);
  534.     }
  535.     if (cacheBlockPtr != (DiskBlock *) NULL) {
  536.     bcopy(bufferPtr, (char *) (cacheBlockPtr+1), bufferSize);
  537.     }
  538.     lfsPtr->pstats.blocksReadDisk += blocks;
  539.     return status;
  540. }
  541.  
  542.  
  543. /*
  544.  *----------------------------------------------------------------------
  545.  *
  546.  * LfsDiskWrite --
  547.  *
  548.  *    Write data to disk.
  549.  *
  550.  * Results:
  551.  *    The number of bytes returned.  -1 if error.
  552.  *
  553.  * Side effects:
  554.  *    None.
  555.  *
  556.  *----------------------------------------------------------------------
  557.  */
  558. int
  559. LfsDiskWrite(lfsPtr, blockOffset, bufferSize, bufferPtr)
  560.     Lfs    *lfsPtr;    /* File system. */
  561.     int    blockOffset;    /* Block offset to start read. */
  562.     char *bufferPtr;    /* Buffer to place data. */
  563.     int     bufferSize;    /* Size of buffer. */
  564. {
  565.     int    status, blockSize, diskFd;
  566.  
  567.     LfsDiskCacheInvalidate(lfsPtr, blockOffset, bufferSize);
  568.     blockSize = LfsBlockSize(lfsPtr);
  569.     diskFd = lfsPtr->diskFd;
  570.  
  571.     /*
  572.      * Seek to the start of the blocks to read.
  573.      */
  574.     status = lseek(diskFd, blockOffset*blockSize, L_SET);
  575.     if (status < 0) {
  576.     fprintf(stderr,"%s:", lfsPtr->deviceName);
  577.     perror("lseek");
  578.     return status;
  579.     }
  580.     status = write(diskFd, bufferPtr, bufferSize);
  581.     if (status != bufferSize) {
  582.     if (status < 0) {
  583.         fprintf(stderr,"%s:", lfsPtr->deviceName);
  584.         perror("write device");
  585.         return status;
  586.     }
  587.     fprintf(stderr,"%s:Short write on device %d != %d\n",lfsPtr->deviceName,
  588.         status, bufferSize);
  589.     } 
  590.     lfsPtr->pstats.blocksWrittenDisk += bufferSize/512;
  591.     return status;
  592. }
  593.  
  594.  
  595.